import os, time, tarfile, hashlib, pickle
def get_md5(fname):  # 计算文件md5值的函数
    m = hashlib.md5()
    frb = open(fname, mode="rb")
    while True:
        data = frb.read(4096)  # 4K
        if len(data) == 0:
            break
        m.update(data)
    frb.close()
    return m.hexdigest()

# cp -r /etc/security /opt
# 备份文件  src: /opt/security   dest: /opt/backup
def incr_backup(src, dest, md5_path):
    # 1. 确定生成 tar 的路径  full -> incr
    fname = os.path.basename(src)  # security
    date = time.strftime("%Y%m%d")  # 20220127
    fname = "%s_incr_%s.tar.gz" % (fname, date)
    # /opt/backup/security_incr_20220127.tar.gz
    tar_fname = os.path.join(dest, fname)
    # 2. 比较今日 new_md5 和昨日 old_md5 中数据的变化，
    #    将新增或者修改的数据添加到tar中进行压缩
    new_md5 = {}  # 今日新的字典
    for item in os.walk(src):
        filename_list = item[2]  # 获取当前目录下的所有文件名组成的列表
        for fname in filename_list:
            filepath = os.path.join(item[0], fname)
            md5_value = get_md5(filepath)
            new_md5[filepath] = md5_value
    print(new_md5["/opt/security/chroot.conf"], "new")
    # 如何获取到昨日旧的字典数据?  pickle.load()  ->  old_dict
    frb = open(md5_path, mode="rb")
    old_dict = pickle.load(frb)  # old_dict: 旧的字典数据
    frb.close()
    print(old_dict["/opt/security/chroot.conf"], "old")
    # 比较 new_md5 字典中每个文件的md5值和old_dict进行对比
    # 比较结果不同，证明文件发生修改或添加，将文件添加tar包中
    tar = tarfile.open(tar_fname, mode="w:gz")
    for filepath in new_md5.keys():
        if new_md5[filepath] != old_dict.get(filepath):
            tar.add(filepath)
    tar.close()
    # 将新字典数据写入磁盘 pickle.dump()
    fwb = open(md5_path, mode="wb")
    pickle.dump(new_md5, fwb)
    fwb.close()

def full_backup(src, dest, md5_path):  # md5_path: 存放md5dict字典文件的路径
    # 1. 确定生成 tar 的路径  项目名_full_日期.tar.gz
    # security_full_20220127.tar.gz
    # !!!!!!src, dest = "/opt/security", "/opt/backup"
    fname = os.path.basename(src)  # security
    date = time.strftime("%Y%m%d")  # 20220127
    fname = "%s_full_%s.tar.gz" % (fname, date)
    # /opt/backup/security_full_20220127.tar.gz
    fname = os.path.join(dest, fname)
    # 2. 给tar包当中添加要压缩的文件
    tar = tarfile.open(fname, mode="w:gz")
    tar.add(src)
    tar.close()
    # 3. 计算每个文件的md5值，保存到字典中，并将字典写入磁盘
    # 获取每个文件的路径
    result = os.walk(src)
    md5dict = {}  # 用于保存每个文件md5值的字典
    # key: 每个文件的路径  value: 每个文件md5值
    for item in result:
        files = item[2]  # 获取当前目录下的所有文件名组成的列表
        for filename in files:    # item[0]: 当前的目录路径
            filepath = os.path.join(item[0], filename)# 生成完整的文件路径
            md5_value = get_md5(filepath)  # 计算每个文件的md5值
            md5dict[filepath] = md5_value  # 将数据添加到md5dict中
    # 4. 将字典写入磁盘当中  pickle.dump()
    fwb = open(md5_path, mode="wb")  # /opt/md5dict.data
    pickle.dump(md5dict, fwb)
    fwb.close()
if __name__ == '__main__':
    src, dest, md5path = "/opt/security", "/opt/backup", "/opt/md5.data"
    now = time.localtime()
    # print(now.tm_wday, type(now.tm_wday))
    if now.tm_wday == 2:  # tm_wday的值为 2 表示周三
        full_backup(src, dest, md5path)
    else:
        incr_backup(src, dest, md5path)
        print("incr~~~~")